home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-03-07 | 41.2 KB | 991 lines | [TEXT/KAHL] |
- O.I.C Objects-in-C (V1.02)
- ===================
-
- Explorer's Kit Documentation
-
- Copyright © John Wainwright, 1988, 1989
-
- 454 West 20th Street, #2
- New York, NY 10011
-
- Compuserve : 72657,2534
-
- All rights reserved
-
- Shareware fee : $20
-
- This is the shareware, explorer's release of a portable
- object-oriented programming environment for the C pro-
- gramming language. The kit contains the complete objects
- environment, a bunch of simple, but useful demo classes
- and this, EXPERTS ONLY, documentation - enough for ex-
- perienced C programmers that know something about object-
- oriented techniques to take advantage of them in the
- excellent C environments now on the Mac.
-
- It is supplied as a verion 3, LightSpeed C project but
- the source files are simple text files that should be
- readable by any of the Macintosh C compilers.
-
- The full release will come with complete documentation
- and an EXTENSIVE set of classes for developing Mac
- applications - a persistent object store, a complete
- Model-View-Controller system for accessing the Mac
- toolbox, 2D & 3D PHIGGS-like imaging spaces integrated
- with the MVC system, a polymorhpic, object-oriented
- spreadsheet system, and an embeddable Common Lisp
- subset interpreter with OIC interface.
-
- Acknowledgements: Tim Long and Andrew Nicholson
- both contributed materially to
- the ideas in this system.
-
-
- ** corresponds to version V1.02 released on Mar 5th, 1989 **
- ** the V1.01 changes are marked with change bars **
-
- Introduction
-
- OIC is a state-of-the-art object-oriented programming environment for
- the C programming language implemented as a portable library of
- management routines and a set of programming conventions. It
- features the following :
-
- • A fully dynamic class structure
- • Multiple inheritence
- • Class variables & class methods
- • Generic function method dispatch with method caching
- • True run-time polymorphism
- • Support for multi-methods
- • No need for a special pre-processor - will work with ANY C
- • High speed access to instance variables via C structures
- • Method dispatch tracing system
- • Smooth & arbitrary transition between C & OOP code
-
- OIC has more of the flavor of the dynamic, Lisp-based OOPS &
- SmallTalk than of the static languages like C++ and Object Pascal.
- Some of the features, like generic functions, are reasonably
- avant-garde, and are described in the following sections.
-
- There is one major departure from the semantics of these OOP systems
- as a consequence of using no pre-processor & deciding to access
- instance variables via C structures: instance variables effectively
- have a SINGLE level of scoping. See the section on Limitations, below
- for a full discussion.
-
- This document assumes a detailed familiarity with C and a reasonable
- understanding of object-oriented programming techniques. For those
- without the latter, try "Object-Oriented Programming for the
- Macintosh" by Kurt Schmucker or "Object-Oriented Programming in
- Common Lisp" by Sonya Keene. The following sections describe the
- implementation approach & memory structures, OIC limitations and
- the example file set. At the end is a reference list of library
- functions & macros, some warnings about portability limitations,
- and details of the shareware licence.
-
- ------------------
-
- Implementation
-
- This section describes the 3 prime elements of the OIC
- system :
-
- • object layout, management and access
- • class layout, management and access
- • generic function & method creation and dispatch
-
- All 3 involve structures created & managed at run-time by the OIC
- library. In this version, ALL the structures are allocated as
- handles, locked & then dereferenced. This is NOT good form, but
- seems to be the quickest memory management scheme on the Mac. If
- it offends you, the storage allocation routines in "memory.c" can
- be changed to suit. The decision to use pointers & not handles
- was to promote portability to C environments other than on the
- Macintosh; a future version may use handles.
-
- Objects
-
- Objects are layed-out in memory as a class tag followed by
- the concatenation of all the instance variables (IVs) defined
- in the object's component classes - i.e., its class and all
- its superclasses, and all their super classes, etc. Each
- object is allocated as a single block of memory and the IVs
- are zero-filled. The class tag defines the object's class
- and is actually a pointer to the class's defining structure
- (described below). The IV's defined by each component class
- are mapped & accessed by ordinary C structures - when a method
- is invoked, a pointer is supplied that points to the local
- IV structure, i.e., the IVs defined in the class in which the
- invoked method was found.
-
- Objects are always referred to by pointers. The provided
- "object" typedef declares a pointer storage type that will
- hold a pointer to ANY class of object - the system is
- dynamically polymorhpic. IVs can be any C type including,
- of course, object.
-
- Objects are created with the "New" function. It takes a
- class & any number of following arguments. When created,
- the object has its "new" generic function invoked which
- is passed the other, presumably initialization, arguments.
-
- It is the programmers responsibilty to explicitly free
- memory occupied by unused objects. The generic function
- "dispose", a method for which is provided in default by
- the root class "Object", will free the originally
- allocated object. This should be specialised
- if any other housekeeping is needed. By convention,
- the generic "deepDispose" will free the object and,
- recursively, any contained objects. This, for example,
- is how the supplied List class lists are freed in one go.
-
- ------------------
-
- Classes
-
- OIC provides full multiple inheritence of methods. This is
- supported by a run-time collection of "Class" objects (yes,
- classes are proper objects) arranged in directed, acyclic
- graph. This D.A.G. maps the inheritence relationships
- among the classes. All classes inherit eventually from
- the root class "Object" which provides a bunch of useful
- default methods. (see "object.c" for its definition).
-
- Each object is tagged by a pointer to its class's object.
- This is how OIC determines an object's class and contrives
- to dispatch the correct method for a given generic function
- invokation. Each class object contains instance allocation
- and IV mapping information, an immediate superclass list,
- the class variables and method invokation information.
- Clearly, a class must exist before any instances of it
- can be created.
-
- The general intention is that each class be defined in a
- separate source file (see examples) to promote information
- hiding, functional independance & all those good things.
- Each file contains the IV & CV structure definitions, a global
- to hold the class object, the methods which are written as
- static functions, and an initializing function that creates
- the class and associates its methods with their generic
- functions (see below).
-
- A class is created by the "NewClass" function. It takes as
- arguments, the size of the IV & CV structures, a class name
- (as a C string) and a null-terminated list of superclasses.
- The order of this list determines the inheritence priority.
- The supplied method finder does a breadth-first search up
- the superclass tree, scanning across the superclass lists
- at each level in the order in which they were specified to
- the NewClass function. Clearly also, "super"classes
- must exist before they can be specialized or mixed-in.
-
- OIC supports class variables and class methods - see the
- "IndexMixin" class for an example of how they work.
-
- ------------------
-
- Generic Functions and Methods
-
- OIC uses the Generic Function (GF) technique of method dispatch,
- prefered in the current state-of-the-art LISP object-oriented
- systems like CLOS, New Flavors, Common Loops, and Object LISP.
- It has several semantic & performance advantages over the
- message passing schemes and embeds exceptionally cleanly in
- functional languages (like C).
-
- Instead of sending a message identifier to an object as in
- SmallTalk, or qualifying a function name by a class name as in
- Object Pascal, the generic function is a single function
- defined over a number of argument classes. It acts like
- a dispatcher which invokes the appropriate method (or methods)
- depending on the class of one (or more) of its arguments and
- hence is "generic". In the terminology a "generic function"
- embodies many operations depending on the class of its
- arguments. The different operations are defined by "method
- functions", one in each of the classes that will directly
- handle that generic.
-
- For example, in a messaging-passing system we might have :
-
- send("append", list, item);
-
- In a GF system this becomes :
-
- append(list, item);
-
- "append" being a function which dispatches to one of the
- various appending methods depending on the class of its first
- argument. This is clearly the preferred form for embedding
- in C. Apart from looking good, a number of neat things follow
- from this technique.
-
- Firstly, it is very simple to write high-speed, caching
- method dispatchers, usually requiring only a single indexing
- operation to get the method required.
-
- Secondly, individual generic functions can be made to have
- their own dispatching semantics by allowing programmers to
- straight-forwardly define their own dispatching functions.
-
- For example, generic functions can be cleanly made to be driven
- by the classes of several arguments, not just one, allowing
- the implementation of so-called multi-methods. In a
- mixed-mode arithmetic system, we might have something like :
-
- add(a, b);
-
- where a & b have different classes & hence some coercion is
- required. A dispatching function for a set of math generic
- functions might look at the classes of the arguments, decide
- on the mutually widest class, invoke coercion generics on
- a & b to that wider class & invoke the add generic on the
- coercions :
-
- add(coerce(a, wide), coerce(b, wide));
-
- Another example might be a dispatching function that will handle
- before, after & around daemon methods in the way of ZetaLisp's Flavors.
-
- Defining Generic Functions
-
- OIC comes supplied with only a single kind of generic function;
- one that dispatches on the class of the first argument -
- equivalent to simple message-passing. If inheritence is
- needed it follows a BREADTH-FIRST search up the superclass tree
- caching any found methods for subsequent single-index dispatch.
-
- Generic functions of this simple type are defined using the
- "defGeneric" macro (defined in "object.h"). This macro is
- unfortunately very unwieldly - it requires 3 arguments which
- are just variants of the generic's name (if ONLY one could
- construct symbols & strings in the standard C preprocessor!!!)
- It declares a function with the generic's name having the
- above-mentioned dispatching semantics and declares some tables
- that hold pointers to the method functions. This method
- table is used by the dispatching code and is in two parts,
- one for normal methods & the other for class methods; they
- are both indexed by a unique "class index" which is allocated
- when the class is created.
-
- Other kinds of dispatching semantics would be implemented by
- defining and using variants of the defGeneric macro. The
- technique allows multiple concurrent defGeneric variants.
-
- Defining & Invoking Method Functions
-
- As mentioned in the Class section above, the various methods
- for a class are usually defined as static functions in that
- class's source file. Method functions are passed 3
- arguments on invokation: the dispatching object, a pointer
- to the local IV structure in that object, and a pointer
- to the rest of the arguments given to the generic. For
- example, the generic invokation :
-
- set(window1, "Untitled", &rect1, VISIBLE);
-
- would result in calling a method function declared :
-
- static object
- set_method(self, ivs, args)
- object self;
- window_iv *ivs;
- struct
- {
- char *title;
- Rect *frame;
- int visFlag;
- } *args;
- {
- .....
- ivs->title = args->title;
- .....
- set_frame(self, args->frame);
- .....
- return self;
- }
-
- such that "self" points to the key object "window1",
- "ivs" points to the "window_iv" structure within that
- object (remember all the IV structures of the component
- classes are concatenated to form an object), and "args"
- points to the string, rectangle & visibility arguments.
-
- The "args" argument actually points into the call frame
- of the generic function "set" at its secondary arguments
- on the stack. This is done for speed & so the dispatcher
- doesn't have to know how many arguments there are. This is
- guaranteed to work only in C implementations that use
- the stack for passing arguments (all the C's on the Mac).
- Some C's on large machines with millions of registers use
- them instead of the stack for argument passing and OIC's
- technique wont work (see portability limitations, below).
-
- Also, on those C's that use the stack, structures are
- layed-out in the same way as arguments on the stack,
- so the in-line argument structure declaration is a neat
- way of getting at these "passed-on" arguments. Remember,
- though, that chars are widened to ints and floats to doubles
- when being placed on the argument stack - they must be
- declared as this widened form in the argument mapping
- struct.
-
- Note in the example, above, how the IVs & arguments are
- accessed in clean, high-speed ways.
-
- Associating Methods with Generic Functions
-
- A generic function is implemented by a bunch of method
- functions, one from each of the classes that is so
- inclined. The association of a method with its generic
- is usually done in the class source file, in the initializing
- function that creates the class (see the example classes).
-
- The function "AddMethod" performs this task and is tuned
- to take a bunch of methods defined in one class & associate them
- one-by-one with each's particular generic. It takes a class object
- as its first argument followed by a null terminated list of
- pairs: the generic's method table (declared by "defGeneric") and
- the method function, e.g.
-
- AddMethods(List, appendGeneric, appendMethod,
- headGeneric, headMethod,
- tailGeneric, tailMethod,
- ....,
- NULL);
-
- AddMethods can be called any time and any number of times after
- a class has been created to incrementally add its methods. An
- equivalently argumented function called "AddClassMethods" will
- add class methods to the generics specified. (see IndexMixin.c
- for an example).
-
- ------------------
-
- Limitations
-
- Embedding such a system in standard C necessarily involes trade-
- offs. Some of these have resulted in limitations and others
- in the need for rather cryptic code.
-
- Scope and Inheritence of Instance Variables
-
- The decision to map object instance variables by C
- structures results in the only major departure from
- conventional OOPS semantics - the SCOPE of instance
- variables is effectively limited to the level in the class
- hierarchy that defines them. This single level of
- scoping immediately implies that ALL instance & class
- variables are inherited; there is no "hiding" of similarly-
- named instance variables up the inheritance chain
- as occurs in some other OOP systems.
-
- Some would contend that this is due & proper adherence
- to the programming principles of encapsulation and,
- fortunately, it rarely causes problems - one tends to be
- interested in the goings-on of the IVs in the
- methods of the class that defined the IVs. However,
- on some occasions, especially when slightly specialising
- an existing class, it is handy to be able to get at the
- IVs for that class, and there are 2 ways to achieve this.
-
- The first is to use one of the macros "localIVs" or "myIVs".
- The first allows you to reach into any object of the same
- class as "self" and get at the IV structure for the current
- method's class. "myIVs" reaches into "self" and gets the
- IVs for any one of its superclasses. See Macros, below for
- further details.
-
- The second way is to provide methods to access IVs. Most
- of the Lisp OOPS do it this way always, the OOPS system
- automatically generating the accessing methods - very easy
- to do in Lisp; not so in C. This technique can, of course,
- be used on an IV-by-IV basis: provide access methods for
- only those that will need to be accessed by specializing
- classes. Because inherited methods have a nested scoping -
- closer ones hide ones farther up the inheritence chain - this
- technique also provides a way of implementing nested
- inheritence of selected IVs.
-
- ------------------
-
- Source File Structure & Coding Conventions
-
- In the example classes and according to the recommended way of
- using OIC there is one source file for each class. This
- yields a convenient modularity and allows the desired
- kinds of information hiding to be set up. Each class
- source file usually contains :
-
- 1. The IV & (possibly) CV structure definitions.
- They will need to be moved out into an include
- file if several classes (which should always
- be inheriting classes) are to get at them.
-
- 2. A class global to hold the class object.
-
- 3. The methods defined in this class, usually
- as static functions. Note in the example
- classes that these are named with the
- generic name prefixed by an underscore; you
- might be happier with the generic name post-
- fixed with "Method" or whatever; in any event,
- they must be different from the actual generic
- function's name.
-
- 4. Any local utility functions that the above might use.
-
- 5. An initializing function that creates the class
- and associates its methods with their corresponding
- generics. This function needs to be called during
- initialization in the main code.
-
- The declaring of generic functions requires some care. They
- are intended to be program-wide globals and are probably best
- all declared in one spot because almost any class might
- wind up defining a method for one. In the example file set
- they are all declared in "generics.c". They also need to be
- declared external in all the source files that might use
- them; in the example kit this is done in the include file
- "generics.h".
-
- Any file that uses OIC should include "oic.h" - it defines
- all the OIC typedefs, macros & externals.
-
- ------------------
-
- Example File Set
-
- This explorer's kit is intended primarily to place a working
- object-oriented C programming mechanism into the hands of
- expert C programmers for their edification, enjoyment and,
- hopefully, serious use. The demo classes and small test
- main program are not intended to be a tutorial on OOPS
- programming, nor to necessarily form the basis for a serious
- suite of classes. They are simply the test classes I built
- as OIC came together, suffer somewhat from its growing
- pains, and are provided to help illuminate the basic
- object manager.
-
- The base object manager is represented in the files :
-
- oic.c - the basic management routines
- memory.c - customizable object allocation routines
- oic.h - the include file for anybody using oic
- Object.c - the root class
- Class.c - the class class
-
- Certain of the class files go to make up the so-called
- system classes :
-
- List.c - a general purpose list class
- String.c - a class to hold C strings
- Replist.c - a representation class for nested objects
- Collect.c - a generic superclass that adds lots of
- neat collection methods to any class that
- provides head, tail, push & eq
- List2.c - a version of the list class using Collect
- IndexMixin.c - a mixin (a modifying superclass) that will
- keep track of all the instances of a class
- that uses it as a superclass
- Linkseq.c - a general purpose sequencing class for
- classes that understand head, tail & isEmpty]
- | DependentsMixin.c - a mixin that keeps a dependents list for
- | its inheritors.
- | StdioStream.c - provides text I/O
- | Name.c - a specialization of string for storing names
- | Binding.c - binds a key object to a value object.
- | HashTable.c - maintains a hashed table of bindings - a
- | lookup table.
- | NameSpace.c - a specialization of HashTable that provides
- | a nested scoping. It is intended that Names be
- | used as keys.
- | NameMixin.c - makes instances of inheriting classes nameable
- | in a global object name space.
- | NameTable.c - a degenerate form of lookup table that uses
- | == comparisons (i.e. good for Names) no hashes.
- | For fast, small lookup tables.
- generics.c - defGenerics for all the above classes
- generics.h - external definitions for the above classes
- | names.h - external definitions for the NameSpace classes
-
- Notes:
-
- 1. The List class does NOT implement standard LISP lists, the
- operations all destructively modify the subject list. It
- will only hold OIC objects as elements.
-
- 2. The IndexMixin class provides an example of how to use
- class variables & class methods. It specializes the "new"
- method & maintains a list (using the List class) of each
- instance of a class inheriting from it in a class variable.
- They can be got by invoking "allInstances" on the class you
- are keeping track of. It also adds a "sequence" class method
- so you can simply sequence over the class. It is an
- example of a so-called "mixin" class, not intended to be
- used on its own but "mixed-in" with some base class usually
- providing some extra behaviour. This kind of class is
- only possible in a multiple inheritance system.
-
- 3. The Replist class is a specialization of the List class
- intended to help formatting & printing nested objects
- like Lists. It gets used by the repList methods in various
- classes to create a structure isomorphic to the object
- being printed but with String representations of the
- object's leaf values instead of the values themselves.
- This can then be neatly parenthesised & indented, etc. See
- how it gets used by looking at the print method in the
- root Object class (object.c). This print method is
- inherited by EVERY class and so provides a simple
- object printer for any class that can generate a Replist
- of itself (see List).
-
- 4. the Linkseq class is an example of what could be
- a suite of sequencing utility classes. Its purpose is
- to wrap up an object that is being sequenced over to
- provide the sequencing context. Note how it gets used
- in the test program, main.c. There are several
- "for" statements that invoke the "sequence" generic on
- an object. Any object that is sequencable should
- define a sequence method that will wrap itself up
- in, and return, one of these utility sequence classes.
- This class should, in turn, respond to the generics
- "start", "next", "moreInSeq", & "restart". Other
- kinds of sequence "wrapper" classes might work for
- scalars by generating consecutive values, strings by
- sequencing through the characters, or arrays by indexing
- through their elements. See how neatly (in main.c) we get
- general purpose polymorphic sequencing in an ordinary
- old C "for" statement.
-
- | 5. The Name class brings a measure of efficiency to the use
- | of Strings as names (in symbol tables, etc). Instances
- | made with the class method "declare" form a proper set,
- | i.e. the string is stored only once and the same string
- | yields identically the same object. This allows ==
- | comparisons on object pointers for name equality and
- | saves space at the same time! In other words, dont use
- | the "New" primitive to create instances, use the class
- | method "declare".
- |
- | The HashTable, Binding & NameSpace classes cooperate
- | to provide a nestable, hashed run-time symbol table
- | capability. They will be used by the Lisp class kit.
-
- A small test program with some other little classes is
- contained in the files :
-
- main.c - the main test procedure
- Coord.c - a kind of point class
- Box.c - a kind of rectangle class
- TestWindow.c - a trivial window class that experiments
- with keyword arguments!
-
- ------------------
-
- OIC System Typedefs
-
- typedef struct class *class - declares a holder for a class object
- typedef struct class **object - declares a holder for an object
- | typedef GenericTable *generic - declares a generic definition table
- | pointer
-
- OIC System Functions
-
- class NewClass(iv_size, cv_size, name, super1, super2, ... NULL)
- int iv_size;
- int cv_size;
- char *name;
- class super1, super2, ...;
-
- creates a new class with local IV & CV structure sizes as given
- and that inherits from the null-terminated list of superclasses.
- The order of this list determines the inheritence priority.
- The supplied method finder does a breadth-first search up
- the superclass tree, scanning across the superclass lists
- at each level in the order in which they were specified to
- the NewClass function.
- The class name is used for debugging & tracing output.
-
- object New(class, initializing arguments ...)
- class class
- <any> initializing arguments ...;
-
- creates a new object of the given class. Invokes the "new"
- generic on the fresh object, passing it the initialization
- arguments.
-
- void AddMethods(class, generic1, method1, generic2, method2, ..., NULL)
- class class;
- MethodTable generic1, generic2, ...;
- <any> (*method1)(), (*method2)() ...;
-
- associates methods for the given class with their generic
- functions. The generics are specified by passing the method
- table that is created by the "defGeneric" macro (see below).
-
-
- void AddClassMethods(class, generic1, method1, generic2, method2, ..., NULL)
- class class;
- MethodTable *generic1, *generic2, ...;
- <any> (*method1)(), (*method2)() ...;
-
- associates class methods for the given class with their generic
- functions. The generics are specified by passing the method
- table that is created by the "defGeneric" macro (see below).
-
- object Super(object, arguments...)
- object object;
- <any> arguments;
-
- invokes the method for the currently executing generic that is
- next higher up the inheritance path than the current method. This
- is very useful when one wishes merely to augment the operation
- of an inherited method, rather than completely replace it.
-
- | object SuperFrom(class, object, arguments...)
- | class class;
- | object object;
- | <any> arguments;
- |
- | same as "Super" but the 'class' argument specifies exactly from
- | which ancestor class to inherit the method. Very useful when
- | using mixin classes to make sure they get a look at "new"s and
- | "dispose"s, for example.
- |
- | All inheritors of DependentsMixin, for example, must use :
- |
- | SuperFrom(DependentsMixin, self);
- |
- | in there "dispose" methods to make sure it disposes the dependents
- | list.
-
- object SuperPassArgs(object, argumentListPtr)
- object object;
- <any> *argumentListPtr;
-
- same as "Super" but a pointer to the argument list is given
- rather than specifying them in place. This is useful for passing
- the argument list pointer that a method normally gets straight
- through to the super method.
-
- | object ApplyGeneric(gen, obj, args)
- | generic gen;
- | object obj;
- | <any> *args;
- |
- | given a generic table reference, dispatches the appropriate
- | method on the given object. Takes a pointer to an argument
- | list. (not the args, themselves). Often used to 'pass on'
- | arguments to another generic:
- |
- | ApplyGeneric(drawGeneric, self, ap);
-
- int SizeOf(object)
- object object;
-
- returns the total size of the object in bytes.
-
- char *ClassNameOf(object)
- object object;
-
- returns the class name of the object as a C string.
-
- char *MethodName(generic)
- MethodTable *generic;
-
- returns the name of a generic as a C string given the generics
- method table (as defined by "defGeneric", see below).
-
- int IsA(object, class)
- object object;
- class class;
-
- returns true if the object is of the given class.
-
- int IsAKindOf(object, class)
- object object;
- class class;
-
- returns true if the object is of the given class or inherits from
- that class.
-
- int IsObj(object)
- object object;
-
- attempts to check whether object is a valid object. It does
- this by ensuring that "object" is a valid pointer, points into
- the application heap, points at a tag that points at a class
- which itself has a tag which must point to the "Class" object.
- It can be fooled, so beware.
-
- void InitOIC()
-
- creates & initializes the OIC system. Should be called
- EXACTLY once before any of the OIC functionality is used.
-
- void InitSysClasses()
-
- creates & initializes the system classes.
-
- void TraceOn() - turns on generic call tracing
- void TraceOff() - turns it off
- void TraceObj(object) - traces any generics called on object
- void TraceClass(class) - traces any generics ony any "class" object
- void dumpClass(class) - debugging class dump
- void dumpMethodTable(mth) - debugging method table dump
-
- OIC System Globals
-
- class currentClass; - the class in which the currently executing
- method was found.
- class classes; - a linked list of all classes created. You can
- get a List of the classes by invoking subs(Object);
- class Class; - the class class.
- class Object; - the root object class. ALL classes inherit
- eventually from Object
- | generic generics; - linked list of generic definition tables
- | object namedObjects; - the NameSpace of named objects (kept by NameMixin)
-
- Object methods
-
- The following methods are provided as defaults by the root class Object.
- ALL classes, therefore, support these methods by default inheritence.
-
- | equal(obj1, obj2) - a byte wise comparison of the contents of each
- new(obj, args...) - dummy "new" method
- className(obj) - class name as a String object
- print(obj) - invokes print(repList(obj))
- repList(obj) - default object representation. creates a
- replist by stepping through obj
- sizeof(object) (4 bytes) at a time. If
- the current 4 bytes is a valid object
- reference recursively calls repList,
- otherwise adds a hex representation to
- the repList
- | map(obj, f, args....) - maps the function "f" over each item in "obj"
- | by using "sequence" on "obj".
- | forAll(obj, f, args...) - identical to "map".
- | forAllGen(obj, gen, argp) - takes a generic table reference & applies
- | its generic over the "sequence" of "obj".
- | cantDo(obj, gen, argp) - invoked if "obj" can't do generic "gen". Prints
- | an error message. This should be specialized by
- | classes that want to handle this their own way.
- | dispose(obj) - frees the memory occupied by "obj". Invalidates
- | the class tag to make it fail any future uses.
-
- Class methods
-
- supers(class) - returns a (List) list of all the classes ancestors
- subs(class) - returns a (List) list of all the classes that
- inherit from "class"
- print(class) - prints the class name
- repList(class) - returns the class name as replist
-
-
- OIC System Macros & Defines
-
- defGeneric(generic, methodTable, name)
-
- declares a generic function and its attendant method table.
- This macro must be called once for each unique generic
- function in the system - generics are global functions.
- The macro is given the generic's name, the name to be used
- for the generic's method table, and the generic's name as
- a C string constant.
-
- If C's preprocessor were even the tiniest bit smart it would
- allow one to create symbols & strings & you have only had to
- give defGeneric one argument. Ah, well.
-
- For example :
-
- defGeneric(print, printGeneric, "print");
-
- externGeneric(generic, methodTable)
-
- declares an external reference to a generic function.
- Usually both the generic function itself and its
- method table need to be accessible, and this macro
- eases their declaration. (see generics.h)
-
- For example :
-
- externGeneric(print, printGeneric);
-
- localIVs(obj, structure)
-
- computes a pointer to the IV structure in "obj" for
- to the current class. This is useful if I'm working
- with two objects of the same class (say, Lists that
- I'm concatenating) and I want to reach into the
- IV's of both of them (see _join in list.c). The
- "structure" argument is just used to cast the
- resulting pointer to that which you want (the
- structure typedef for the current class's IVs).
-
- myIVs(class, structure)
-
- computes a pointer to the IVs of "self" for the
- given "class". This is the macro that gets around
- the one-level scoping problem - I can reach back
- and get at the IVs of any superclass I want (providing
- the structure typedefs are available - you may
- want to enforce the hiding by keeping these typedefs
- private).
-
- localCVs(class, structure)
-
- as for localIVs but point at the class variables instead.
-
- myCVs(class, structure)
-
- as for myIVs but point at the class variables instead.
-
- | IVs(obj, class, structure)
- |
- | computes a pointer to the IV structure in "obj" from
- | "class". The "structure" argument is just used to
- | cast the resulting pointer to that which you want (the
- | structure typedef for the current class's IVs).
- |
- | CVs(obj, class, structure)
- |
- | same as IVs but returns a pointer to the "class"es
- | CV structure.
-
- ClassOf(object)
-
- computes the class of the given object
-
- | method
- |
- | just a synonym for "static" to make method function
- | declarations look more like methods.
-
- CHECK_OBJS
-
- if defined in "oic.c" will cause all oic functions to
- check for valid class & object arguments (by using IsObj()).
- This is a conditional assembly flag and is set on in the
- distributed kit.
-
- | IGNORE_NULL_OBJS
- |
- | if defined in "oic.c" causes method dispatch to detect
- | a NULL pointer as the dispatching object and simply
- | return NULL without complaining. This is useful if you
- | frequently checking for NULL objects (often in IVs as
- | they are initialized NULL) before invoking generics on them.
- | But, beware, this prevents CHECK_OBJS from detecting
- | NULL objects which is often a frequent bug in early
- | development. You will have to choose whether you want the
- | convenience of not having to detetct NULL objects or
- | the safety of error checking.
-
- END
-
- equivalent to NULL. Used sometimes to mark the end
- of argument lists. Another gripe: why didnt they
- design C so you could find out how many arguments you
- were given - after all, the function call form is
- completely polymorphic - I can understand the lack in
- a language with compile-time isomorphism checks like
- Pascal.
-
- ------------------
-
- Portability Considerations
-
- There is really only one major portability consideration and that
- involves OIC's expectations about the use of the stack for passing
- arguments. It expects all arguments to be placed on the stack
- with earlier arguments at lower addresses.
- On 680x0s and 80x86s there is no other sensible option and so
- OIC should port without trouble on C compilers for those machines
- (the techniques have been tried on 68010 Unix 4.2BSD and 80286
- Xenix & MS-DOS boxes succesfully).
-
- OIC was developed in THINK's Lightspeed C, an extremely good C
- development environment for the Macintosh. It has also run without
- change using Aztec C.
-
- The current version does make use of UNIX-like standard I/O calls
- for outputing errors and trace messages. Both LSC and Aztec provide
- a Unix emulation library for this. You may have trouble if your C
- doesn't, in which case you should recode all the printf's &
- fprintf's. Indeed, in the full OIC, this use of Unix emulation
- will go and be replaced by the use of generic, stream-based text
- window classes.
-
- ------------------
-
- | Tips on using OIC with the THINK LSC Debugger on the Macintosh
- |
- | There is one problem and a couple of tricks associated with using the
- | THINK C Debugger. The debugger wont correctly "step" into a generic
- | function invokation. This is because the source for the generic
- | dispatching code is hidden in a macro expansion and the debugger likes
- | to have actual source to show as it is stepping. THINK is looking
- | at this problem but apparently it is hard to fix. The only thing
- | to do at the moment is to manually place a break-point in the method
- | you expect the generic to invoke and "go" to it.
- |
- | Inspecting objects in the data window requires some tricks. If you just
- | keep derefering an object pointer you will wind up examining it's
- | class structure (which, of course, you may want to do). If however,
- | you want to see the IV structure then you should use the IV accessing
- | macros; fortunately the data window accepts macros. So, to see the
- | local IVs of self, use
- |
- | localIVs(self, xxxx_i) /* xxxx is the IV structure typedef */
- |
- | If you want to look inside an arbitrary object, use
- |
- | IVs(obj, class, xxxx_i)
- |
- | This will display the IV's of "obj" for the given "class". It will be
- | necessary in this case to have the IV structure declaration available.
- | It is useful, during debugging, to have one header file containing all
- | the IV structure declarations temporarily included in each file for this
- | purpose.
-
- ------------------
-
- Licensing Terms
-
- This software is distributed as shareware; if you wind up using it
- for developing any software, particularly commercial software, please
- send the $20 fee to the address below. You will become a registered
- user and have access to upgrades & class kits as they become
- available.
-
- The software is also distributed AS IS, with no warranty, expressed or
- implied, of the correctness or suitability of this software for any purpose.
- No responsibility is assumed for damages arising from the use of this
- software.
-
- OIC is protected by copyright and all commercial rights are reserved.
- Under NO circumstances may this software be distributed in any decodable
- source form, or any form that might be usable as a programming tool
- for commercial advantage. Reasonable duplication costs can be charged.
-
- Under the shareware ethic, however, you are free to copy & distribute
- the OIC software UNCHANGED, providing this document & licensing terms
- are also copied & distributed with the OIC software.
-
- Feedback & queries are welcome. I am interested in any classes that
- you may develop - indeed, it seems to me that the success
- of a system like this will primarily be a function of the quantity and
- quality of classes available.
-
-
- Have fun!
-
- John Wainwright
- 454 West 20th Street, #2
- New York, NY 10011
-
- Compuserve : 72657,2534
-
-
- All OIC files & documentation are Copyright © John Wainwright, 1988, 1989